<route lang="json5" type="page">
{
  layout: 'default',
  style: {
    navigationBarTitleText: '订单管理',
  },
}
</route>

<template>
  <view class="container">
    <view class="sticky">
      <wd-search
        v-model="searchText"
        cancel-txt="搜索"
        placeholder="输入订单号搜索"
        @search="onSearch"
        @clear="onClear"
      >
        <template #suffix>
          <view class="filter-trigger">
            <wd-icon
              name="filter1"
              size="20px"
              color="#4d80f0"
              class="filter-icon"
              @click="filterVisible = true"
            />
          </view>
        </template>
      </wd-search>
    </view>

    <wd-popup v-model="filterVisible" position="right">
      <view class="filter-panel">
        <view class="filter-title">筛选</view>
        <wd-calendar type="daterange" v-model="calendarRange" @confirm="onCalendarConfirm" />
        <view class="filter-actions">
          <wd-button size="small" plain @click="resetCalendar">重置</wd-button>
          <wd-button size="small" type="primary" @click="applyAndClose">应用</wd-button>
        </view>
      </view>
    </wd-popup>

    <wd-card custom-title-class="summary-card">
      <view class="summary-grid">
        <view class="metric metric-amount">
          <text class="metric-label">订单总金额</text>
          <text class="metric-number">￥{{ (orderTotalAmount || 0) / 100 }}</text>
        </view>
        <view class="metric metric-count">
          <text class="metric-label">订单单数</text>
          <text class="metric-number">{{ orderCount || 0 }}</text>
        </view>
        <view class="metric metric-refund-amount">
          <text class="metric-label">退款总金额</text>
          <text class="metric-number">￥{{ (refundTotalAmount || 0) / 100 }}</text>
        </view>
        <view class="metric metric-refund-count">
          <text class="metric-label">退款单数</text>
          <text class="metric-number">{{ refundCount || 0 }}</text>
        </view>
      </view>
    </wd-card>

    <view class="list-wrapper">
      <view v-if="renderList.length === 0 && state !== 'loading'" class="empty">
        <uni-icons type="list" size="36" color="#cccccc" />
        <text class="empty-text">暂无订单</text>
      </view>

      <view v-for="item in renderList" :key="item.id" class="order-card">
        <view class="row header">
          <text class="title">{{ formatDevice(item) }}</text>
          <wd-tag :type="statusType(item.payStatus)" shape="fillet">
            {{ statusText(item.payStatus) }}
          </wd-tag>
        </view>

        <view class="row info">
          <text class="label">支付类型</text>
          <wd-tag :type="payTypeTag(item.payType)" shape="fillet">
            {{ payTypeText(item.payType) }}
          </wd-tag>
        </view>

        <view class="row info">
          <text class="label">店铺</text>
          <view class="value avatar-line">
            <image
              class="avatar-sm"
              :src="item.deviceBindAvatarUrl || '/static/app/icons/96x96.png'"
              mode="aspectFill"
            />
            <text class="value-text">{{ item.deviceBindNickName || '-' }}</text>
          </view>
        </view>

        <view class="row info">
          <text class="label">订单号</text>
          <text class="value mono">{{ item.orderNo }}</text>
        </view>

        <view class="row info">
          <text class="label">金额</text>
          <div>
            <text class="value price">￥{{ (item.payAmount || 0) / 100 }}</text>
            <text v-if="formatPackage(item)" class="pkg">{{ formatPackage(item) }}</text>
          </div>
        </view>

        <view class="row meta">
          <uni-icons type="calendar" size="16" color="#999" />
          <text class="time">{{ formatTime(item.createTime) }}</text>
        </view>
      </view>
    </view>

    <wd-loadmore :state="state" @reload="loadmore" />
  </view>
</template>

<script lang="ts" setup>
import { onLoad, onReachBottom } from '@dcloudio/uni-app'
import { httpPost } from '@/utils/http'
import dayjs from 'dayjs'

const list = ref<any[]>([])
const num = ref<number>(1)
const max = ref<number>(20)

const filterDate = ref<string>('')
const startDate = ref<string>('')
const endDate = ref<string>('')
const filterVisible = ref<boolean>(false)
const calendarRange = ref<any>('')
const deviceBindUserId = ref<number>(0)
const orderTotalAmount = ref<number>(0)
const orderCount = ref<number>(0)
const refundTotalAmount = ref<number>(0)
const refundCount = ref<number>(0)

const getList = async () => {
  const body: any = {
    page: num.value,
    size: 20,
  }
  if (startDate.value) {
    body.createTime = `${startDate.value} 00:00:00`
  }
  if (endDate.value) {
    body.endTime = `${endDate.value} 23:59:59`
  }
  if (!startDate.value && !endDate.value && filterDate.value) {
    body.createTime = `${filterDate.value} 00:00:00`
    body.endTime = `${filterDate.value} 23:59:59`
  }
  if (deviceBindUserId.value) {
    body.deviceBindUserId = deviceBindUserId.value
  }
  if ((searchText.value || '').trim()) {
    body.keyWord = (searchText.value || '').trim()
  }
  const _res: any = await httpPost('/api/app/order/order/pageSummary', body)

  list.value = [...(list.value ?? []), ...(_res?.list ?? [])]
  max.value = _res.pagination?.total || 0
  orderTotalAmount.value = Number(_res?.summary?.orderTotalAmount || 0)
  orderCount.value = Number(_res?.summary?.orderCount || 0)
  refundTotalAmount.value = Number(_res?.summary?.refundTotalAmount || 0)
  refundCount.value = Number(_res?.summary?.refundCount || 0)
  state.value = 'finished'
}
const state = ref<any>('loading')

onReachBottom(() => {
  if (list?.value?.length < max.value) {
    loadmore()
  } else if (list?.value?.length === max.value) {
    state.value = 'finished'
  }
})

onLoad((_options: any) => {
  if (_options?.date) {
    filterDate.value = _options.date
    startDate.value = _options.date
    endDate.value = _options.date
  }
  if (_options?.deviceBindUserId) {
    deviceBindUserId.value = Number(_options.deviceBindUserId)
  }
  if (_options?.createTime) {
    startDate.value = String(_options.createTime).slice(0, 10)
  }
  if (_options?.endTime) {
    endDate.value = String(_options.endTime).slice(0, 10)
  }
  getList()
})

function loadmore() {
  num.value = num.value + 1
  getList()
}

const searchText = ref<string>('')
const renderList = computed(() => {
  let arr = list.value || []
  if (payTypeFilter.value) {
    arr = arr.filter((e: any) => Number(e.payType || 0) === payTypeFilter.value)
  }
  return arr
})

function onSearch() {
  num.value = 1
  list.value = []
  state.value = 'loading'
  getList()
}
function onClear() {
  searchText.value = ''
  num.value = 1
  list.value = []
  state.value = 'loading'
  getList()
}

function applyDateFilter() {
  num.value = 1
  list.value = []
  state.value = 'loading'
  getList()
}

function applyAndClose() {
  if (Array.isArray(calendarRange.value) && calendarRange.value.length === 2) {
    const s = dayjs(calendarRange.value[0])
    const e = dayjs(calendarRange.value[1])
    startDate.value = s.format('YYYY-MM-DD')
    endDate.value = e.format('YYYY-MM-DD')
  }
  applyDateFilter()
  filterVisible.value = false
}

function onCalendarConfirm({ value }: any) {
  if (Array.isArray(value) && value.length === 2) {
    const s = dayjs(value[0])
    const e = dayjs(value[1])
    startDate.value = s.format('YYYY-MM-DD')
    endDate.value = e.format('YYYY-MM-DD')
  }
}

function resetCalendar() {
  calendarRange.value = ''
  startDate.value = ''
  endDate.value = ''
}

function formatTime(t: any) {
  if (!t) return ''
  return dayjs(t).format('YYYY-MM-DD HH:mm:ss')
}
function formatPackage(row: any) {
  try {
    if (!row?.packageContent) return ''
    const p = JSON.parse(row.packageContent)
    if (!p) return ''
    const price = p?.packagePrice ? p.packagePrice / 100 : ''
    const count = p?.gameCount ?? ''
    if (price && count) return `${price}元=${count}币`
    return ''
  } catch {
    return ''
  }
}
function formatDevice(row: any) {
  return `设备：${row?.deviceNo || '-'}`
}
function statusText(s: number) {
  if (s === 1) return '已支付'
  if (s === 2) return '已关闭'
  if (s === 3) return '已退款' 
}
function statusType(s: number) {
  if (s === 1) return 'success'
  if (s === 2) return 'danger'
  return 'warning'
}

const payTypeFilter = ref<number>(0)
function payTypeText(s: number) {
  if (s === 2) return '支付宝'
  return '微信'
}
function payTypeTag(s: number) {
  if (s === 2) return 'primary'
  return 'success'
}
</script>

<style lang="scss" scoped>
.sticky {
  position: sticky;
  top: 0;
  z-index: 10;
  background: #f7f7f7;
  padding: 20rpx 24rpx;
}
.seg-wrap {
  margin-top: 16rpx;
}
.filter-trigger {
  display: flex;
  justify-content: flex-end;
  margin-top: 8rpx;
}
.filter-icon {
  padding: 8rpx;
}
.filter-panel {
  width: 86vw;
  background: #fff;
  border-radius: 16rpx;
  padding: 24rpx;
}
.filter-title {
  font-size: 30rpx;
  color: #333;
  margin-bottom: 16rpx;
}
.quick-tags {
  display: flex;
  gap: 12rpx;
  margin-bottom: 16rpx;
}
.picker-row {
  display: flex;
  align-items: center;
  gap: 12rpx;
}
.divider {
  color: #999;
}
.filter-actions {
  display: flex;
  justify-content: flex-end;
  gap: 12rpx;
  margin-top: 16rpx;
}
.summary-card {
  margin: 0 !important;
  padding: 0 !important;
}
.summary-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16rpx;
}
.metric {
  border-radius: 16rpx;
  padding: 24rpx;
  color: #fff;
  display: flex;
  flex-direction: column;
  gap: 8rpx;
}
.metric-label {
  font-size: 24rpx;
  opacity: 0.9;
}
.metric-number {
  font-size: 32rpx;
  font-weight: 600;
}
.metric-amount {
  background: linear-gradient(135deg, #4d80f0, #7aa7ff);
}
.metric-count {
  background: linear-gradient(135deg, #6cbd7a, #8fe39a);
}
.metric-refund-amount {
  background: linear-gradient(135deg, #ff7a7a, #ffb3b3);
}
.metric-refund-count {
  background: linear-gradient(135deg, #f0a64d, #ffd07a);
}
.list-wrapper {
  padding: 24rpx;
}
.order-card {
  background: #fff;
  border-radius: 20rpx;
  padding: 28rpx;
  margin-bottom: 24rpx;
  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.04);
}
.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.header {
  margin-bottom: 16rpx;
}
.title {
  font-size: 30rpx;
  color: #333;
}
.info {
  margin: 10rpx 0;
}
.label {
  color: #666;
  font-size: 26rpx;
}
.value {
  color: #333;
  font-size: 28rpx;
}
.avatar-line {
  display: flex;
  align-items: center;
}
.avatar-sm {
  width: 40rpx;
  height: 40rpx;
  border-radius: 50%;
  margin-right: 12rpx;
}
.value-text {
  line-height: 40rpx;
}
.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
    'Courier New', monospace;
}
.price {
  color: #e60012;
  font-weight: 600;
}
.pkg {
  margin-left: 12rpx;
  color: #999;
  font-size: 24rpx;
}
.meta {
  margin-top: 8rpx;
  color: #999;
  gap: 8rpx;
}
.empty {
  padding: 60rpx 24rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16rpx;
}
.empty-text {
  color: #999;
  font-size: 28rpx;
}
</style>
